package example;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 先来描述一下它的使用场景：有若干个线程，比如说有五个线程，需要它们都到达了某一个点之后才能开始一起执行，
 * 也就是说假如其中只有四个线程到达了这个点，还差一个线程没到达，此时这四个线程都会进入等待状态，
 * 直到第五个线程也到达了这个点之后，这五个线程才开始一起进行执行状态
 *
 * @author dengzhiyuan
 * @version 1.0
 * @describe
 * @time 2023/3/19 21:48
 */
public class CyclicBarrierExample {

//    CyclicBarrier(int parties, Runnable barrierAction): 创建一个 CyclicBarrier 对象，需要指定线程数量和屏障点任务。
//
//    await(): 调用该方法的线程会等待其他线程到达屏障点，直到所有线程都到达屏障点后，屏障点任务才会被执行，
//    然后所有线程继续执行各自的任务。如果当前线程是最后一个到达屏障点的线程，则它会唤醒其他等待的线程，让它们继续执行任务。
//
//    await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException,
//    TimeoutException: 调用该方法的线程会等待其他线程到达屏障点，但是如果等待时间超过了指定的 timeout，则会抛出 TimeoutException 异常，
//    表示等待超时。如果在等待过程中发生了中断，则会抛出 InterruptedException 异常。如果在等待过程中有其他线程调用了 reset() 方法，
//    或者在 await() 方法调用时已经抛出了 BrokenBarrierException 异常，则会抛出 BrokenBarrierException 异常。
//
//    getNumberWaiting(): 返回当前等待在屏障点的线程数量，不包括当前线程。
//
//    reset(): 将屏障重置为初始状态，这样后续调用 await() 方法的线程将重新等待其他线程到达屏障点。
//
//    这些方法可以帮助我们实现复杂的多线程协调和同步逻辑。需要注意的是，CyclicBarrier 的实现是可重用的，也就是说，一旦屏障点任务被执行，它就可以被重复使用。



    private static final int THREAD_COUNT = 3;

    public static void main(String[] args) {
        // 创建一个 CyclicBarrier 对象，需要指定线程数量和屏障点任务
        CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT, () -> {
            System.out.println("所有线程都到达了屏障点");
        });

        // 创建若干个线程并启动
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " 正在执行任务");
                    // 调用 await 方法等待其他线程到达屏障点
                    barrier.await();
                    System.out.println(Thread.currentThread().getName() + " 继续执行任务");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
